﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Windows;

using System.Threading;
using System.IO.Ports;
using ETRoboCon.SwitchBoxProtocol;

namespace ETRoboCon.TrackingSystem.TakahashiSwitchBox
{

    class COMPortAdapter
    {
        private SerialPort port = null;
        private bool opened = false;
        private SwitchBoxProtocol.ISBPSerializer sbSerializer = new SwitchBoxProtocol.SBPSerializer();
        private Thread receiveThread;
        private Mutex myLock;

        public COMPortAdapter()
        {
            myLock = new Mutex(false);
        }

        public void Open(string portName)
        {
            port = new SerialPort(portName);
            port.BaudRate = 115200;
            port.Parity = Parity.None;
            port.StopBits = StopBits.One;
            port.DataBits = 8;

            receiveThread = new Thread(COMPortAdapter.ReceiveWork);
            receiveThread.Start(this);
        }

        public void Close()
        {
            myLock.WaitOne();
            if (opened)
            {
                opened = false;
            }
            myLock.ReleaseMutex();
        }

        public bool Opened
        {
            get
            {
                myLock.WaitOne();
                bool status = opened;
                myLock.ReleaseMutex();
                return status;
            }
        }

        public delegate void SwitchPushedDelegator(ETRoboConTrakingSystem.SwitchBoxButtonType switchId, long tick);

        public event SwitchPushedDelegator OnSwitchPushed;

        public static void ReceiveWork(object instance)
        {
            COMPortAdapter adapter = instance as COMPortAdapter;
            adapter.ReceiveWorking();
        }

        private void ReceiveWorking()
        {
            try
            {
                port.Open();
                myLock.WaitOne();
                opened = true;
                bool status = opened;
                myLock.ReleaseMutex();
                while (true)
                {
                    try
                    {
                        ReceiveData();
                    }
                    catch (System.SystemException ex)
                    {
                        myLock.WaitOne();
                        opened = false;
                        myLock.ReleaseMutex();
                        break;
                    }
                }
                port.Close();
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (port.BytesToRead > 0)
            {
                ReceiveData();

            }
        }

        private void ReceiveData()
        {
            int count = 10;
            byte[] received = new byte[count];
            int offset = 0;
            int receivedBytes = 0;
            while (count > 0)
            {
                receivedBytes = port.Read(received, offset, count);
                offset += receivedBytes;
                count -= receivedBytes;
            }
            if (OnSwitchPushed != null)
            {
                ushort value = received[0];
                if (value >> 4 == 0x05)
                {
                    value &= 0x0f;
                    received[0] = (byte)value;
                    bool[] buttonsStatus = new bool[(int)SwitchBoxProtocol.ButtonKind.NUM_OF_BUTTON];
                    int tick = sbSerializer.DeserializeSwitchBoxButtonOrder(received, out buttonsStatus) / 10;
                    for (int i = 0; i < buttonsStatus.Length; i++)
                    {
                        if (buttonsStatus[i])
                        {
                            if (i == (int)SwitchBoxProtocol.ButtonKind.BUTTON_START)
                            {
                                OnSwitchPushed(ETRoboConTrakingSystem.SwitchBoxButtonType.START, tick);
                            }
                            else if (i == (int)SwitchBoxProtocol.ButtonKind.BUTTON_CANCEL)
                            {
                                OnSwitchPushed(ETRoboConTrakingSystem.SwitchBoxButtonType.RESET, tick);
                            }
                            else if (i == (int)SwitchBoxProtocol.ButtonKind.BUTTON_IN_GOAL)
                            {
                                OnSwitchPushed(ETRoboConTrakingSystem.SwitchBoxButtonType.GOAL_IN, tick);
                            }
                            else if (i == (int)SwitchBoxProtocol.ButtonKind.BUTTON_IN_RETIRE)
                            {
                                OnSwitchPushed(ETRoboConTrakingSystem.SwitchBoxButtonType.RETIRE_IN, tick);
                            }
                            else if (i == (int)SwitchBoxProtocol.ButtonKind.BUTTON_OUT_GOAL)
                            {
                                OnSwitchPushed(ETRoboConTrakingSystem.SwitchBoxButtonType.GOAL_OUT, tick);
                            }
                            else if (i == (int)SwitchBoxProtocol.ButtonKind.BUTTON_OUT_RETIRE)
                            {
                                OnSwitchPushed(ETRoboConTrakingSystem.SwitchBoxButtonType.RETIRE_OUT, tick);
                            }
                        }
                    }
                }
            }
        }
        public void UpdateSwitchLightStatus(bool start, bool reset, bool goalIn, bool retireIn, bool goalOut, bool retireOut)
        {
            bool[] buttonStatus = new bool[(int)SwitchBoxProtocol.ButtonKind.NUM_OF_BUTTON];
            if (start)
            {
                buttonStatus[(int)SwitchBoxProtocol.ButtonKind.BUTTON_START] = true;
            }
            if (reset)
            {
                buttonStatus[(int)SwitchBoxProtocol.ButtonKind.BUTTON_CANCEL] = true;
            }
            if (goalIn)
            {
                buttonStatus[(int)SwitchBoxProtocol.ButtonKind.BUTTON_IN_GOAL] = true;
            }
            if (retireIn)
            {
                buttonStatus[(int)SwitchBoxProtocol.ButtonKind.BUTTON_IN_RETIRE] = true;
            }
            if (goalOut)
            {
                buttonStatus[(int)SwitchBoxProtocol.ButtonKind.BUTTON_OUT_GOAL] = true;
            }
            if (retireOut)
            {
                buttonStatus[(int)SwitchBoxProtocol.ButtonKind.BUTTON_OUT_RETIRE] = true;
            }

            byte[] order;
            sbSerializer.SerializeSwitchBoxBoxLampOrder(buttonStatus, out order);
            port.Write(order, 0, order.Length);
        }

    }
}
